import docker
from flask import jsonify,Response,request
from app import db, DOCKER_CLIENT


class ContainerService:
    @staticmethod
    def get_all_containers():
        # 获取所有容器列表
        containers = DOCKER_CLIENT.containers.list(all=True)

        containers_info = map(lambda container: {
            "id": container.id,
            "name": container.name,
            "image": container.image.tags[0] if container.image.tags else "None",
            "status": container.status,
            "Create_Time": container.attrs['Created'].replace('T', ' ')[:19],
            "command": container.attrs['Args'],
            "ports": container.attrs['NetworkSettings']['Ports'],
        }, containers)
        return list(containers_info)

    @staticmethod
    def start_containers(container_id):
        try:
            container = DOCKER_CLIENT.containers.get(container_id)
            if container.status == "running":
                return jsonify({
                    "message": "Container already started",
                })
            container.start()
            return jsonify({
                "message": f"Container {container_id} started successfully"
            }),200
        except docker.errors.NotFound:
            return jsonify({
                "message": f"Container {container_id} not found"
            }), 404
        except docker.errors.APIError as e:
            return jsonify({
                "message": f"Failed to start container {container_id}",
                "error": str(e)
            }), 500

    @staticmethod
    def stop_containers(container_id):
        try:
            container = DOCKER_CLIENT.containers.get(container_id)
            if container.status == "stopped" or container.status == "exited":
                return jsonify({
                    "message": "Container already stopped",
                })
            container.stop()
            return jsonify({
                "message": f"Container {container_id} stopped successfully"
            }), 200
        except docker.errors.NotFound:
            return jsonify({
                "message": f"Container {container_id} not found"
            }), 404
        except docker.errors.APIError as e:
            return jsonify({
                "message": f"Failed to stop container {container_id}",
                "error": str(e)
            }), 500

    @staticmethod
    def remove_container(container_id):
        try:
            container = DOCKER_CLIENT.containers.get(container_id)
            if container.status == "running":
                container.stop()
                container.remove(force=True)
                return jsonify({
                    "message": f"Container {container_id} remove successfully"
                }),200
            container.remove(force=True)
            return jsonify({
                "message": f"Container {container_id} remove successfully"
            }), 200
        except docker.errors.NotFound:
            return jsonify({
                "message": f"Container {container_id} not found"
            }), 404
        except docker.errors.APIError as e:
            return jsonify({
                "message": f"Failed to remove container {container_id}",
                "error": str(e)
            }), 500

    @staticmethod
    def logs_container(container_id):
        try:
            container = DOCKER_CLIENT.containers.get(container_id)
            logs = container.logs(stream=True, follow=True)  # 实时获取日志流

            def generate():
                for line in logs:
                    yield line.decode('utf-8') + "\n"  # 逐行返回日志

            return Response(generate(), content_type='text/plain')
        except docker.errors.NotFound:
            return f"Container {container_id} not found.", 404
        except Exception as e:
            return f"An error occurred: {str(e)}", 500

    @staticmethod
    def create_container():
        try:
            # 获取请求参数,json方式
            # image_name = request.json.get('image_name')  # 必填
            # container_name = request.json.get('container_name')  # 必填
            # host_port = request.json.get('host_port')  # 可选
            # container_port = request.json.get('container_port')  # 可选
            # host_volume = request.json.get('host_volume')  # 可选
            # container_volume = request.json.get('container_volume')  # 可选

            # 获取请求参数，表单方式
            image_name = request.form.get('image_name')  # 必填
            container_name = request.form.get('container_name')  # 必填
            host_port = request.form.get('host_port')  # 可选
            container_port = request.form.get('container_port')  # 可选
            host_volume = request.form.get('host_volume')  # 可选
            container_volume = request.form.get('container_volume')  # 可选

            # 检查必填字段
            if not image_name or not container_name:
                return jsonify({'error': 'image_name 和 container_name 是必填字段'}), 400

            # 校验端口映射参数
            if (host_port and not container_port) or (not host_port and container_port):
                return jsonify({"error": "host_port 和 container_port 必须同时传递，或者都不传递"}), 400

            # 处理端口映射
            ports = {}
            if host_port and container_port:
                ports[container_port] = int(host_port)

            # 处理卷组映射
            volumes = {}
            if host_volume and container_volume:
                volumes[host_volume] = {"bind": container_volume, "mode": "rw"}

            # 创建容器
            container = DOCKER_CLIENT.containers.run(
                image=image_name,
                name=container_name,
                ports=ports if ports else None,  # 如果有端口映射则传入，否则不映射
                volumes=volumes if volumes else None,  # 如果有卷组映射则传入，否则不映射
                detach=True  # 后台运行
            )

            # 返回容器ID
            return jsonify({"container_id": container.id}), 200
        except Exception as e:
            return jsonify({"error": str(e)}), 500